Cloudflare D1
Cloudflareのエッジで動作するサーバーレスSQLite
Cloudflare Workersからネイティブに接続でき、SQLiteの全機能が使える
ローカル開発時は、Miniflare経由で普通のSQLiteでエミュレートされる
/mrsekut-book-9784297154387/020
https://blog.cloudflare.com/introducing-d1/
https://zenn.dev/mizchi/articles/cloudflare-d1
魂が震えるらしい
Claude Code.icon
セットアップ
DB作成
λ wrangler d1 create
DB作成
code:bash
wrangler d1 create my-database
出力されるIDを wrangler.toml に設定:
code:toml
d1_databases
binding = "DB"
database_name = "my-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
スキーマ作成
λ wrangler d1 execute
code:bash
wrangler d1 execute my-database --command "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE, created_at TEXT DEFAULT (datetime('now')))"
またはSQLファイルから:
code:bash
wrangler d1 execute my-database --file schema.sql
Workers からの基本操作
code:ts
export default {
async fetch(request: Request, env: Env) {
const { DB } = env;
// SELECT
const users = await DB.prepare("SELECT * FROM users WHERE id = ?")
.bind(1)
.first(); // 1行取得
// 複数行取得
const allUsers = await DB.prepare("SELECT * FROM users")
.all();
// allUsers.results → 配列
// INSERT
await DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)")
.bind("Alice", "alice@example.com")
.run();
// UPDATE
await DB.prepare("UPDATE users SET name = ? WHERE id = ?")
.bind("Bob", 1)
.run();
// DELETE
await DB.prepare("DELETE FROM users WHERE id = ?")
.bind(1)
.run();
return Response.json(users);
},
};
クエリメソッド
table:_
メソッド 戻り値 用途
.first() 1行(オブジェクト or null) 単一レコード取得
.first(column) 特定カラムの値 first("name") → "Alice"
.all() { results, success, meta } 複数行取得
.run() { success, meta } INSERT/UPDATE/DELETE
.raw() 配列の配列 ヘッダーなしの生データ
バッチ実行
複数クエリをまとめてトランザクション的に実行:
code:ts
const results = await DB.batch([
DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Alice"),
DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Bob"),
DB.prepare("SELECT * FROM users"),
]);
// results2.results → 全ユーザー
batch() 内のクエリは暗黙のトランザクションで実行される
途中で失敗すると全体がロールバック
マイグレーション
code:bash
# マイグレーションファイル作成
wrangler d1 migrations create my-database add-posts-table
# → migrations/0001_add-posts-table.sql が生成される
# マイグレーション適用(ローカル)
wrangler d1 migrations apply my-database --local
# マイグレーション適用(リモート)
wrangler d1 migrations apply my-database --remote
ローカル開発
code:bash
# ローカルDBで開発(--local がデフォルト)
wrangler dev
# ローカルDBに直接SQLを実行
wrangler d1 execute my-database --local --command "SELECT * FROM users"
ローカルDBは .wrangler/state/v3/d1/ に保存される。
Time Travel(ポイントインタイムリカバリ)
D1は自動的にWAL(Write-Ahead Log)を保持しており、過去の任意の時点に復元できる。
code:bash
# ブックマーク一覧(復元ポイント)
wrangler d1 time-travel info my-database
# 特定の時点に復元
wrangler d1 time-travel restore my-database --timestamp "2026-03-20T10:00:00Z"
# ブックマーク指定で復元
wrangler d1 time-travel restore my-database --bookmark <bookmark>
保持期間: Freeプランで30日、Paidプランで30日。
Session API(リードレプリカ対応)
code:ts
const session = DB.withSession("first-unconsumed");
// セッション内のクエリはリードレプリカ活用 + 因果一貫性を保証
const user = await session.prepare("SELECT * FROM users WHERE id = ?")
.bind(1)
.first();
table:_
セッションモード 動作
"first-primary" 最初のクエリはプライマリ、以降はレプリカ
"first-unconsumed" 未消費のブックマーク付きならレプリカから
"none" セッションなし(デフォルト動作)
型定義(TypeScript)
code:ts
interface Env {
DB: D1Database;
}
// 型付きクエリ
interface User {
id: number;
name: string;
email: string;
}
const user = await DB.prepare("SELECT * FROM users WHERE id = ?")
.bind(1)
.first<User>();
// user: User | null
制限事項
table:_
項目 Free Paid
DBの数 10 50,000
最大DBサイズ 500MB 10GB
読み取り 500万行/日 500億行/月
書き込み 10万行/日 5,000万行/月
1クエリの最大結果 20MB 20MB
注意点
SQLiteベースなのでJOINやサブクエリ、ウィンドウ関数などが使える
ただしALTER TABLEは SQLite の制約に従う(カラム削除は SQLite 3.35.0+ で対応済み)
Workers の 1 リクエスト内でのクエリ数に実質上限はないが、CPU時間制限(Free: 10ms, Paid: 30s)に注意
batch() はネットワークラウンドトリップが1回なので、個別実行より高速